package org.langcom.log;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;

/**
 * Purposed for improving standart java logging * A pattern consists of a string that includes the following special components that will be replaced at runtime:
 * <ul>
 * <li>"/" the local pathname separator
 * <li>"%a" the eclipse application directory
 * <li>"%t" the system temporary directory
 * <li>"%h" the value of the "user.home" system property
 * <li>"%g" the generation number to distinguish rotated logs
 * <li>"%u" a unique number to resolve conflicts
 * <li>"%%" translates to a single percent sign "%"
 * </ul>
 * 
 * @author nemo
 * 
 */
public class LookLog {

	private static Map<String, Logger> loggerMap = new HashMap<String, Logger>();
	private static boolean isDefault = false;

	private LookLog() {
	}

	public static void init() {
		try {
			LogManager.getLogManager().readConfiguration(new LookLogInit().getProps().toStream());
		} catch (Throwable e) {
			e.printStackTrace();
			isDefault = true;
		}
	}

	public static Logger getLog(String className, Level level) {
		try {
			Logger log = loggerMap.get(className + "_" + level.getName()); //$NON-NLS-1$
			if (log == null) {
				log = getNewLog(className, level);
			}
			return log;
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void log(String className, Level level, String msg) {
		if (isDefault) {
			System.out.println("default :  " + className + ":  " + " Level:  " + level.getName() + "   :   " + msg);
			return;
		}
		Logger logger = getLog(className, level);
		if (logger != null) {
			logger.log(level, msg);
		} else {
			System.out.println("+" + msg);
		}
	}

	public static void info(String className, String msg) {
		if (isDefault) {
			System.out.println("default :  " + className + ":  " + " Level:  " + Level.INFO.getName() + "   :   " + msg);
			return;
		}
		Logger logger = getLog(className, Level.INFO);
		if (logger != null) {
			logger.log(Level.INFO, msg);
		} else {
			System.out.println("+" + msg);
		}
	}

	public static void error(String className, String msg) {
		if (isDefault) {
			System.out.println("default :  " + className + ":  " + " Level:  " + Level.SEVERE.getName() + "   :   " + msg);
			return;
		}
		Logger logger = getLog(className, Level.SEVERE);
		if (logger != null) {
			logger.log(Level.SEVERE, msg);
		} else {
			System.out.println("+" + msg);
		}
	}

	public static void error(String className, String msg, Throwable err) {
		if (isDefault) {
			System.out.println("default :  " + className + ":  " + " Level:  " + Level.SEVERE.getName() + "   :   " + err.getMessage());
			return;
		}
		Logger logger = getLog(className, Level.SEVERE);
		if (logger != null) {
			logger.log(Level.SEVERE, msg, err);
		} else {
			System.out.println("+" + msg);
		}
	}

	public static void warning(String className, String msg) {
		if (isDefault) {
			System.out.println("default :  " + className + ":  " + " Level:  " + Level.WARNING.getName() + "   :   " + msg);
			return;
		}
		Logger logger = getLog(className, Level.WARNING);
		if (logger != null) {
			logger.log(Level.WARNING, msg);
		} else {
			System.out.println("+" + msg);
		}
	}

	public static Logger getNewLog(String className, Level level) {
		Logger log = Logger.getLogger(className);
		if (log == null) {
			log = Logger.getAnonymousLogger();
		}
		log.setLevel(level);
		return log;
	}

	public static IStatus getIStatus(Throwable e, String pluginId, String errorMessage) {
		MultiStatus status = new MultiStatus(pluginId, IStatus.ERROR, errorMessage, e);
		for (StackTraceElement element : e.getStackTrace()) {
			status.add(new Status(IStatus.ERROR, pluginId, element.toString()));
		}
		if (e.getCause() != null) {
			status.add(getIStatusInt(e.getCause(), 0, pluginId, errorMessage));
		}
		return status;
	}

	private static IStatus getIStatusInt(Throwable e, int level, String pluginId, String errorMessage) {
		MultiStatus status = new MultiStatus(pluginId, IStatus.ERROR, errorMessage, e);
		if (level > 8) {
			return status;
		}
		for (StackTraceElement element : e.getStackTrace()) {
			status.add(new Status(IStatus.ERROR, pluginId, element.toString()));
		}
		if (e.getCause() != null) {
			status.add(getIStatusInt(e.getCause(), level++, pluginId, errorMessage));
		}
		return status;
	}

	/**
	 * The Level class defines a set of standard logging levels that can be used to control logging output. The logging Level objects are ordered and are specified by ordered integers. Enabling
	 * logging at a given level also enables logging at all higher levels.
	 * <p>
	 * Clients should normally use the predefined Level constants such as Level.SEVERE.
	 * <p>
	 * The levels in descending order are:
	 * <ul>
	 * <li>SEVERE (highest value)
	 * <li>WARNING
	 * <li>INFO
	 * <li>CONFIG
	 * <li>FINE
	 * <li>FINER
	 * <li>FINEST (lowest value)
	 * </ul>
	 * In addition there is a level OFF that can be used to turn off logging, and a level ALL that can be used to enable logging of all messages.
	 * <p>
	 * It is possible for third parties to define additional logging levels by subclassing Level. In such cases subclasses should take care to chose unique integer level values and to ensure that they
	 * maintain the Object uniqueness property across serialization by defining a suitable readResolve method.
	 * 
	 * @version 1.20, 11/17/05
	 * @since 1.4
	 */
	public static void setDefault(boolean isDefault) {
		LookLog.isDefault = isDefault;
	}
}
